/**
 * 220106:增加updateForFrame的time和frame参数
 * 221011: restructuring with typescript, major alteration.
 */
 import {EventDispatcher, WebGLRenderer} from 'three';
import WorkSpace from './work-space';
 
 
 interface RatioRect{
    top: number, left: number, ratioWidth: number, width: number, ratioHeight: number, height: number
 }
 interface Spaces{
    [id:string]:WorkSpace,
 }
 interface ResizeHandler{
    (size:RatioRect):void,
 }
 interface ResizeHandles{
    [id:string]:ResizeHandler,
 }
 interface ShiftSceneHandler{
    (newId:string|null,oldId:string|null):void,
 }

 class SceneManagerEventConfig{
    public static readonly resize:string='onResize';
    public static readonly shiftScene:string = 'onShiftScene';
 }
 class ResizeEventParas{
    public value:RatioRect|null;
    constructor(size:RatioRect|null){
        this.value=size;
    }
}
class ResizeEventObject{
    public readonly type:string=SceneManagerEventConfig.resize;
    public readonly paras:ResizeEventParas;
    constructor(size:RatioRect|null){
        this.paras=new ResizeEventParas(size);
    }
}; 
interface ResizeHandle{
    (eventObject:ResizeEventObject):void;
}
class ShiftSceneEventParas{
    public current:string|null;
    public previous:string|null;
    constructor(current:string|null,previous:string|null){
        this.current=current;
        this.previous=previous;
    }
}
class ShiftSceneEventObject{
    public readonly type:string=SceneManagerEventConfig.shiftScene;
    public readonly paras:ShiftSceneEventParas;
    constructor(current:string|null,previous:string|null){
        this.paras=new ShiftSceneEventParas(current,previous);
    }
}; 
interface ShiftSceneHandle{
    (eventObject:ShiftSceneEventObject):void;
}

 //multiple scene management
 class SceneManager{

     private _renderId:string|null=null;
     private _size:DOMRect=new DOMRect();
     private _oriSize:DOMRect=new DOMRect();
     private _rSize!:RatioRect;
     private _spaces!:Spaces;
     private _resizeCall!:ResizeHandles;
     private fireResizeEvent!:ResizeHandler;
     private fireShiftSceneEvent!:ShiftSceneHandler;
     private _resizeEvent!:ResizeEventObject;
     private _shiftSceneEvent!:ShiftSceneEventObject;
     
     public readonly renderer:WebGLRenderer;
     public readonly eventCenter:EventDispatcher=new EventDispatcher();

     constructor(renderer:WebGLRenderer,size:DOMRect){
         this.renderer=renderer;
         this._size=size;
         this.copyDomRect(size,this._oriSize);
         this.init();
     }
 
     /**
      * 获取渲染rect
      */
     public get size(){
         return this._rSize;
     }
 
     /**
      * 设置渲染rect
      */
     public set size(size:DOMRect|RatioRect){
         if(size) this._size = size as DOMRect;
         this._rSize.left = this._size.left;
         this._rSize.top = this._size.top;
         this._rSize.width = this._size.width;
         this._rSize.height = this._size.height;
         this._rSize.ratioWidth = this._size.width / this._oriSize.width;
         this._rSize.ratioHeight = this._size.height / this._oriSize.height;
 
         for(let id in this._spaces){
             this._spaces[''+id+''].resize(this._rSize);
         }
 
         this.renderer.setSize(this._size.width, this._size.height);
         for (let key in this._resizeCall) {
             if (this._resizeCall['' + key + '']) this._resizeCall['' + key + ''](this._rSize);
         }
         this.fireResizeEvent(this._rSize);
     }
 
     /**
      * 设置窗体尺寸改变时的回调
      */
     public set resizeCall(key_funcSize:[key:string,func:ResizeHandler]){
         this._resizeCall[''+key_funcSize[0]+'']=key_funcSize[1];
     }
 
     /**
      * 获取所包含的工作空间
      */
     public get childSpace(){
         return this._spaces;
     }
 
     /**
      * 获取当前渲染空间ID
      */
     public get renderId(){
         return this._renderId;
     }
 
     /**
      * 设置渲染空间ID
      */
     public set renderId(id:string|null){
         if(id==this._renderId)return;
         this.fireShiftSceneEvent(id,this._renderId);
         this._renderId=id;
     }
 
     /**
      * 更新渲染调用
      */
     public updateForFrame(time:number,frame:XRFrame):void {
         if (!this.renderer.autoClear) this.renderer.clear();
         if(this.renderId)this._spaces[''+this.renderId+''].render(this.renderer,time,frame);
     }
 
     /**
      * 添加到空间渲染队列
      */
     public addToQueue(space:WorkSpace):void {
         for(let id in this._spaces){
             if(id===space.uuid){
                 console.warn('cannot add the same space to render queue for twice!');
                 return;
             }
         }
         this._spaces[''+space.uuid+'']=space;
     }
 
     /**
      * 从空间渲染队列移除
      */
     public removeFromQueue(space:WorkSpace):void{
         if(!this._spaces[''+space.uuid+''])return;
         delete this._spaces[''+space.uuid+''];
     }
 
 
     private initEventBind():void{
         this.fireResizeEvent=(size:RatioRect)=>{
             this._resizeEvent.paras.value=size;
             this.eventCenter.dispatchEvent(this._resizeEvent);
         };
         this.fireShiftSceneEvent=(nId,oId)=>{
             this._shiftSceneEvent.paras.current=nId;
             this._shiftSceneEvent.paras.previous=oId;
             this.eventCenter.dispatchEvent(this._shiftSceneEvent);
         };
     }
     private init():void{
         this.initVariable();
         this.initComponents();
         this.initEventBind();
     }

     private initVariable():void{
         this._spaces={};
         this._resizeCall={};
         this._rSize = {left:0, top:0, width:0, height:0, ratioWidth:1, ratioHeight:1};
         this._resizeEvent=new ResizeEventObject(null);
         this._shiftSceneEvent=new ShiftSceneEventObject(null,null);
     }
     private initComponents():void{
         this.initSize();
     }
     private initSize():void{
         this._rSize.left = this._size.left;
         this._rSize.top = this._size.top;
         this._rSize.width = this._size.width;
         this._rSize.height = this._size.height;
         this._rSize.ratioWidth = this._size.width / this._oriSize.width;
         this._rSize.ratioHeight = this._size.height / this._oriSize.height;
     }
     private copyDomRect(f:DOMRect,t:DOMRect):void{
        t.x=f.x;
        t.y=f.y;
        t.width=f.width;
        t.height=f.height;
     }
 }

 export {SceneManager,SceneManagerEventConfig,ResizeEventObject,ShiftSceneEventObject};
 export type {ResizeHandle,ShiftSceneHandle,RatioRect};